package guda.grape;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created by well on 15/3/17.
 */
public class TimeoutService {

    private Logger log = LoggerFactory.getLogger(TimeoutService.class);


    private TreeSet<TaskEvent> task = new TreeSet<TaskEvent>();
    private volatile boolean taskCheckRuningFlag = false;
    private static Map<String, Command> commandMap;

    private TaskCheck taskCheck;

    //注册超时处理逻辑
    static {
        commandMap = new HashMap<String, Command>();
        commandMap.put(EventTypeEnum.DEMO1_TIMEOUT.name(), new Demo1TimeoutCommand());
        commandMap.put(EventTypeEnum.DEMO2_TIMEOUT.name(), new Demo2TimeoutCommand());
    }

    public void register(TaskEvent taskEvent) {
        if (taskEvent == null) {
            return;
        }
        if (log.isInfoEnabled()) {
            log.info("注册超时任务:" + taskEvent.getEventId());
        }
        if (!task.isEmpty()) {
            TaskEvent first = task.first();
            if (taskEvent.getExecuteTime() < (first.getExecuteTime())) {
                if (taskCheck != null) {
                    taskCheck.cancel();
                }
            }
        }
        task.add(taskEvent);
        startTaskCheck();
    }

    public synchronized void unRegister(TaskEvent taskEvent) {
        if (taskEvent == null) {
            return;
        }
        if (log.isInfoEnabled()) {
            log.info("取消超时任务,taskEvent=" + taskEvent.getEventId());
        }
        if (!task.remove(taskEvent)) {
            log.warn("取消超时任务，忽略，任务已经处理,taskEvent=" + taskEvent.getEventId());
            return;
        }
        log.warn("取消超时任务成功，taskEvent=" + taskEvent.getEventId());
        //如果任务是当前在进行中
        if (taskCheck != null && taskCheck.getCurrentTaskEvent().equals(taskEvent)) {
            taskCheck.cancel();
            startTaskCheck();
            log.warn("取消超时任务成功，当前任务在进行中，taskEvent=" + taskEvent.getEventId());
        }

    }

    public synchronized void stop(TaskEvent taskEvent) {
        if (taskEvent == null) {
            return;
        }
        if (log.isInfoEnabled()) {
            log.info("停止超时任务,taskEvent=" + taskEvent.getEventId());
        }

        //如果任务是当前在进行中
        if (taskCheck != null && taskCheck.getCurrentTaskEvent().equals(taskEvent)) {
            taskCheck.cancel();
            startTaskCheck();
            log.warn("停止超时任务成功，当前任务在进行中，taskEvent=" + taskEvent.getEventId());
        } else {
            task.remove(taskEvent);
            log.warn("停止超时任务成功，taskEvent=" + taskEvent.getEventId());
        }

    }


    public synchronized void startTaskCheck() {
        if (!taskCheckRuningFlag) {
            taskCheckRuningFlag = true;
            taskCheck = new TaskCheck();
            taskCheck.setDaemon(true);
            taskCheck.start();
        }


    }


    public class TaskCheck extends Thread {

        private Timer timer = new Timer();
        private TaskEvent currentTaskEvent;

        public TaskEvent getCurrentTaskEvent() {
            return currentTaskEvent;
        }

        public void cancel() {
            try {
                if (timer != null) {
                    timer.cancel();
                    taskCheckRuningFlag = false;
                    log.info("task cancel,task=" + currentTaskEvent.getEventId());
                }
                this.interrupt();
            } catch (Exception e) {

            }
        }

        @Override
        public void run() {
            if (task.isEmpty()) {
                taskCheckRuningFlag = false;
                return;
            }

            final TaskEvent taskEvent = task.first();
            currentTaskEvent = taskEvent;
            long time = taskEvent.getExecuteTime();
            if (time - System.currentTimeMillis() <= 0) {

                Command command = commandMap.get(taskEvent.getEventType());
                try {
                    command.exec(taskEvent, new TaskFuture() {
                        @Override
                        public void finish() {
                            taskCheckRuningFlag = false;
                            task.pollFirst();
                            startTaskCheck();

                        }
                    });
                } catch (Exception e) {
                    log.error("", e);
                }
            } else {
                try {
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            Command command = commandMap.get(taskEvent.getEventType());
                            command.exec(taskEvent, new TaskFuture() {
                                @Override
                                public void finish() {
                                    taskCheckRuningFlag = false;
                                    task.pollFirst();
                                    startTaskCheck();
                                }
                            });
                        }
                    }, time - System.currentTimeMillis());

                } catch (Exception e) {
                    log.error("", e);
                }
            }

        }
    }


    public void setCommandMap(Map<String, Command> commandMap) {
        this.commandMap = commandMap;
    }


}
